#include "../../include/system/ReportGenerator.h"
#include "../../include/core/Transaction.h"
#include "../../include/core/Customer.h"
#include "../../include/core/BankAccount.h"
#include "../../include/system/Utils.h"

#include <vector>
#include <string>
#include <fstream>
#include <algorithm>
#include <iterator>
#include <iostream>
#include <iomanip>

namespace MiniBanking
{

    // --- Private Helper Implementation ---
    bool ReportGenerator::writeTransactionsToFile(const std::string &filename,
                                                  const std::string &reportTitle,
                                                  const std::vector<Transaction> &transactions)
    {
        std::ofstream reportFile(filename);
        if (!reportFile.is_open())
        {
            std::cerr << "Error [ReportGenerator]: Could not open file '" << filename << "' for writing.\n";
            return false;
        }

        reportFile << "===== " << reportTitle << " (" << Utils::getCurrentDateTimeString() << ") =====\n\n";
        reportFile << std::fixed << std::setprecision(2); // Format currency

        if (transactions.empty())
        {
            reportFile << "(No transactions to display)\n";
        }
        else
        {
            for (const auto &tx : transactions)
            {
                reportFile << "ID: " << tx.getID()
                           << " | Time: " << Utils::formatTimestamp(tx.getTimestamp())
                           << " | Type: " << transactionTypeToString(tx.getType())
                           << " | Amount:  ¥" << tx.getAmount(); // Yen Symbol UTF-8

                // Add From/To details based on type
                if (tx.getType() == TransactionType::DEPOSIT)
                {
                    reportFile << " | To: " << tx.getDestinationAccountID();
                }
                else if (tx.getType() == TransactionType::WITHDRAW)
                {
                    reportFile << " | From: " << tx.getSourceAccountID();
                }
                else if (tx.getType() == TransactionType::TRANSFER)
                {
                    reportFile << " | From: " << tx.getSourceAccountID() << " | To: " << tx.getDestinationAccountID();
                }

                if (!tx.getNote().empty())
                {
                    reportFile << " | Note: " << tx.getNote();
                }
                reportFile << "\n";
            }
        }

        reportFile << "\n===== End of Report =====\n";
        reportFile.close();
        return true;
    }

    // --- Public Static Method Implementations ---

    std::string ReportGenerator::generateGlobalReport(const std::vector<Transaction> &allTransactions)
    {
        // 1. Create filename
        std::string filename = "transactions_" + Utils::getCurrentDateString() + ".txt";

        // 2. Sort transactions (make a copy first to avoid modifying original)
        std::vector<Transaction> sortedTransactions = allTransactions;
        std::sort(sortedTransactions.begin(), sortedTransactions.end());

        // 3. Write to file using helper
        std::string reportTitle = "Global Transaction Report";
        if (writeTransactionsToFile(filename, reportTitle, sortedTransactions))
        {
            return filename;
        }
        else
        {
            return ""; // Indicate failure
        }
    }

    std::string ReportGenerator::generateCustomerReport(const Customer &customer,
                                                        const std::vector<Transaction> &allTransactions)
    {
        // 1. Create filename
        std::string safeCustomerName = Utils::sanitizeFilenamePart(customer.getName());
        std::string filename = "transactions_" + safeCustomerName + "_" + Utils::getCurrentDateString() + ".txt";

        // 2. Filter transactions for this customer's accounts
        std::vector<Transaction> customerTransactions;
        std::string savingsID = customer.getSavingsAccountID();
        std::string checkingID = customer.getCheckingAccountID();

        std::copy_if(allTransactions.begin(), allTransactions.end(),
                     std::back_inserter(customerTransactions),
                     [&](const Transaction &tx)
                     {
                         return tx.getSourceAccountID() == savingsID || tx.getDestinationAccountID() == savingsID ||
                                tx.getSourceAccountID() == checkingID || tx.getDestinationAccountID() == checkingID;
                     });

        // 3. Sort the filtered transactions
        std::sort(customerTransactions.begin(), customerTransactions.end());

        // 4. Write to file using helper
        std::string reportTitle = "Customer Transaction Report: " + customer.getName();
        if (writeTransactionsToFile(filename, reportTitle, customerTransactions))
        {
            return filename;
        }
        else
        {
            return ""; // Indicate failure
        }
    }

    std::string ReportGenerator::generateAccountReport(const BankAccount &account,
                                                       const std::vector<Transaction> &allTransactions)
    {
        // 1. Create filename
        std::string accountID = account.getAccountID();
        // Account IDs should already be filename-safe, but sanitize just in case
        std::string safeAccountID = Utils::sanitizeFilenamePart(accountID);
        std::string filename = "transactions_" + safeAccountID + "_" + Utils::getCurrentDateString() + ".txt";

        // 2. Filter transactions involving this account
        std::vector<Transaction> accountTransactions;
        std::copy_if(allTransactions.begin(), allTransactions.end(),
                     std::back_inserter(accountTransactions),
                     [&](const Transaction &tx)
                     {
                         return tx.getSourceAccountID() == accountID || tx.getDestinationAccountID() == accountID;
                     });

        // 3. Sort the filtered transactions
        std::sort(accountTransactions.begin(), accountTransactions.end());

        // 4. Write to file using helper
        std::string reportTitle = "Account Transaction Report: " + accountID;
        if (writeTransactionsToFile(filename, reportTitle, accountTransactions))
        {
            return filename;
        }
        else
        {
            return "";
        }
    }

}
